#ifndef _UTILS_H_
#define _UTILS_H_

#include<string>
#include<string.h>


std::string& strtolower(std::string& s);
std::string& strtoupper(std::string& s);


class StringRef {
private:
	const char *m_pstr;
	size_t m_length;
public:
	enum { npos = (size_t)(-1) };

	StringRef():m_pstr(0),m_length(0) { }
	StringRef(const std::string& str):m_pstr(str.data()),m_length(str.length()) { }
	StringRef(const char *str, size_t len):m_pstr(str),m_length(len) { }
	StringRef(const char * str):m_pstr(str),m_length(str?strlen(str):0) { }

	const char *str() const { return m_pstr; }
	size_t length() const { return m_length; }
	char operator[](size_t i) const { return m_pstr[i]; }

	void str(const char *str, size_t len)
	{
		m_pstr = str;
		m_length = len;
	}

	void str(const char *str)
	{
		m_pstr = str;
		m_length = (str?strlen(str):0);
	}

	bool isnull() const { return (m_pstr==0); }
	bool empty() const { return (m_length==0); }

	size_t find(char c, size_t pos = 0)
	{
		for(size_t i = pos; i < m_length; ++i) {
			if( m_pstr[i] == c ) 
				return i;
		}

		return npos;
	}

	size_t find(StringRef needle, size_t pos = 0)
	{
		const char *t = needle.str();
		size_t nlen = needle.length(); 

		if((nlen+pos)>m_length || m_pstr==NULL) 
			return npos;
		
		if(nlen == 0) 
			return 0;

		//////////////////////////////////////////////////////////////////////////
		// str:    AAABCCXXXEEFFF
		// needle:   XXX
		size_t n = m_length - pos - nlen + 1;
		size_t i,j;
		//printf("%d,%d,%d\n",haystack.length(),nlen,n);
		const char *s = m_pstr + pos;
		for(i = 0; i < n; ++i,++s) {
			if(*s == *t) {
				j = 1;
				while(j<nlen && s[j]==t[j]) ++j;
				
				if(j == nlen) 
					return (i + pos);
			}
		}
		return npos;
	}
};

static int xstrncmp(const char *s1, const char *s2, size_t len) 
{
	const char *e1 = s1 + len;
	for (; s1 != e1; s1++, s2++) {
		if (*s1 < *s2) {
			return -1;
		} else if (*s1 > *s2) {
			return 1;
		}
	}
	return 0;
}

static bool operator== (StringRef lhs, StringRef rhs)
{
	return (lhs.length()==rhs.length() && xstrncmp(lhs.str(),rhs.str(),lhs.length())==0);
}

static bool operator!= (StringRef lhs, StringRef rhs)
{
	return (lhs.length()!=rhs.length() || xstrncmp(lhs.str(),rhs.str(),lhs.length())!=0);
}

static bool operator< (StringRef lhs, StringRef rhs)
{
	int result = xstrncmp(lhs.str(), rhs.str(), lhs.length()>rhs.length()?rhs.length():lhs.length());
	if(result == 0) result = (int)lhs.length() - (int)rhs.length();
	return result<0;
}

static bool operator> (StringRef lhs, StringRef rhs)
{
	int result = xstrncmp(lhs.str(), rhs.str(), lhs.length()>rhs.length()?rhs.length():lhs.length());
	if(result == 0) result = (int)lhs.length() - (int)rhs.length();
	return result>0;
}

#endif //_UTILS_H_
